#include "swarmSocketClient.h"
#include <iostream>
#include <fcntl.h>
#include <cstring>
#include <csignal>
using namespace std;

void
init_sockaddr (struct sockaddr_in *name,
                    const char *hostname,
                    uint16_t port)
     {
       struct hostent *hostinfo;
     
       name->sin_family = AF_INET;
       name->sin_port = htons (port);
       hostinfo = gethostbyname (hostname);
       if (hostinfo == NULL)
         {
           //fprintf (stderr, "Unknown host %s.\n", hostname);
           //exit (EXIT_FAILURE);
         }
       name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
     }

//end init_sockaddr
swarmSocketClient::swarmSocketClient(const char* hst, int pt)
{
	this->serverHost = new char[strlen(hst)];
	strcpy(this->serverHost, hst);
	this->port = pt;
	//initclient();
	
}
swarmSocketClient::swarmSocketClient(){};
int swarmSocketClient::initclient()
{
	sock = socket (PF_INET, SOCK_STREAM, 0);
	if (sock < 0)
        {
		return -1;
           	//perror ("socket (client)");
        	//exit (EXIT_FAILURE);
	}
	init_sockaddr (&servername, serverHost, port);
	int flags = fcntl(sock, F_GETFL, 0);
	fcntl(sock, F_SETFL, flags | O_NONBLOCK);
	if (0 > connect (sock,
                        (struct sockaddr *) &servername,
                        sizeof (servername)) && errno != EINPROGRESS)
         {
		//perror ("connect (client)");
		//sleep(10);
		return -2;
           	//
           	//exit (EXIT_FAILURE);
         }
	tv.tv_sec = 2;
	tv.tv_usec = 0;//600000;
	errno = 0;
	FD_ZERO(&read_fd_set);
	FD_SET (sock, &read_fd_set);
	errno = 0;
	int k = select(sock+1, NULL, &read_fd_set, NULL, &tv);
	//cout<< "select " << k << endl;
	if(k < 0)
	{
		//perror("k:");
		return k;
	}
	if(!FD_ISSET(sock, &read_fd_set))
	{
		return -3;
	}
	return 0;	
}
int swarmSocketClient::initclient(const char* hst, int pt)
{
	this->serverHost = new char[strlen(hst)];
	strcpy(this->serverHost, hst);
	this->port = pt;
	return initclient();
}
int swarmSocketClient::writeMessage(const void* message,int size)
{
	signal (SIGPIPE, SIG_IGN);
	int nbytes, y;
	char buffer[500];
	////perror("go1");
	tv.tv_sec = 5;
	tv.tv_usec = 0;
	FD_ZERO(&read_fd_set);
	FD_SET (sock, &read_fd_set);
	nbytes = select(sock+1, NULL, &read_fd_set, NULL, &tv);
	if(!FD_ISSET(sock, &read_fd_set))
	{
		////perror("could not write");
		return -2;
	}
	nbytes = write (sock, message, size + 1);
	y = nbytes;//save number of bytes sent
	////perror("go2");
	if (nbytes < 0 || nbytes != (size+1))
	{
		////perror("too few bytes written");
	   return nbytes;//if only partial message sent return number of characters successfully sent
	}
	tv.tv_sec = 5;
	tv.tv_usec = 0;
	////perror("go3");
	FD_ZERO(&read_fd_set);
	FD_SET (sock, &read_fd_set);
	nbytes = select(sock+1, &read_fd_set, NULL, NULL, &tv);
	if(!FD_ISSET(sock, &read_fd_set))
	{
		//perror("could not read");
		//cout <<"why " << y << " " << (errno == EPIPE) << endl;
		//cout << "nbytes " << nbytes << " sec " << tv.tv_sec << " usec " << tv.tv_usec << endl;
		return -3;//if no acknowledgment received in 5 seconds assume server is down and return and error
		//nbytes = read(sock, buffer, 500 + 1);
		//fprintf (stderr, "bytes%i tv%i buf%s\n",nbytes, tv.tv_sec, buffer);
		////perror("read1");
		//exit (EXIT_FAILURE);
	}
	////cout << "select = " << nbytes << endl;
	nbytes = read(sock, buffer, 500 + 1);
	if(nbytes <= 0 )//if error in the read return error
	{
		////perror("nbytes <= 0 on read");
		////cout <<"nbytes <= 0 " << nbytes << endl;
		return nbytes;//std:://cout<< "message " << buffer << " " << nbytes << " " << tv.tv_sec << "b";
	}
	////perror("got to end");
	////cout <<"nbytes = " << nbytes << " bytes written = " << endl;
	return y;
	
}
bool swarmSocketClient::checkConnection()
{
	//signal (SIGPIPE, SIG_IGN);
	int nbytes, readbytes;
	/*int nbytes, y;*/
	char buffer[500];
	////perror("go1");
	tv.tv_sec = 1;
	tv.tv_usec = 0;
	FD_ZERO(&read_fd_set);
	FD_SET (sock, &read_fd_set);
	readbytes = select(sock+1, &read_fd_set, NULL, NULL, &tv);
	////cout << "readbytes " << readbytes << " fd_isset" << FD_ISSET(sock, &read_fd_set) << endl;	
	readbytes = read(sock, buffer, 500 + 1);
	////cout << readbytes << endl;
	nbytes = writeMessage("ack", 3);
	//cout << nbytes;
	if(nbytes < 3)//!FD_ISSET(sock, &read_fd_set) || nbytes < 0)
	{
		return false;
	}
	else
	{
		return true;
	}
}
void swarmSocketClient::shut()
{
	//delete [] this->serverHost;
	close(sock);
}
swarmSocketClient::~swarmSocketClient()
{
	//delete [] this->serverHost;
	close (sock);
}
